import { Component, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core';
import { FormBuilder, UntypedFormControl, UntypedFormGroup, Validators } from '@angular/forms';
import { NzMessageService } from 'ng-zorro-antd/message';
import { ApiService } from 'src/app/services/api.service';
import { AddRoleParam } from 'src/app/models/param/add-role.param';
import { Consts } from 'src/app/consts/consts';
import { MenuDto } from 'src/app/models/sys/menu.dto';
import { MenuQueryParam } from 'src/app/models/param/menu-query.param';
import { NzFormatEmitEvent, NzTreeComponent, NzTreeNodeOptions } from 'ng-zorro-antd/tree';
import { EditMode } from 'src/app/models/enums/edit-mode.enum';
import { BehaviorSubject } from 'rxjs';
import { RoleDto } from 'src/app/models/sys/role.dto';
import { UpdateRoleParam } from 'src/app/models/param/update-role.param';
import { DictDto } from 'src/app/models/sys/dict.dto';
import { GroupDto } from 'src/app/models/sys/group.dto';
import { PageParam } from 'src/app/models/param/page.param';
import { GroupQueryParam } from 'src/app/models/param/group-query.param';

const ROLE_NAME = 'roleName';
const ROLE_KEY = 'roleKey';
const ORDER_NUM = 'orderNum';
const ENABLED = 'enabled';
const REMARK = 'remark';

@Component({
  selector: 'app-add-role',
  templateUrl: './add-role.component.html',
  styleUrl: './add-role.component.less'
})
export class AddRoleComponent implements OnInit {
  @Input() modeSubject!: BehaviorSubject<{mode: EditMode, roleId?: number}>;

  @Output() addRoleEvent = new EventEmitter<boolean>();
  @ViewChild('nzTreeComponent', { static: false }) nzTreeComponent!: NzTreeComponent;
  
  // 新建还是编辑
  role?: RoleDto;
  modeEnum = EditMode;
  editMode = EditMode.ADD;

  // form fields
  addForm!: UntypedFormGroup;
  
  nodes: NzTreeNodeOptions[] = [];
  defaultCheckedKeys:string[] = [];
  selectedKeys: string[] = [];
  expandedKeys = [];

  // 分组选择
  selectedGroupTypeId = 0;
  selectedGroupIds: number[] = [];
  groupTypes: DictDto[] = [];
  groups: GroupDto[] = [];

  submitted = false;

  constructor(private _api: ApiService,
    private _fb: FormBuilder,
    private _message: NzMessageService) {}

  ngOnInit(): void {
    this.createAddForm();
    this.getMenus();
    this.getGroupTypes();
  }
    
  createAddForm() {
    console.log('createAddForm');
    this.addForm = this._fb.group({});
    this.addForm.addControl(ROLE_NAME, new UntypedFormControl('', [Validators.minLength(2), Validators.maxLength(20)]));
    this.addForm.addControl(ROLE_KEY, new UntypedFormControl('', [Validators.minLength(2), Validators.maxLength(20)]));
    this.addForm.addControl(ORDER_NUM, new UntypedFormControl('', [Validators.pattern('^[0-9]*$'), Validators.max(1000000)]));
    this.addForm.addControl(ENABLED, new UntypedFormControl(''));
    this.addForm.addControl(REMARK, new UntypedFormControl('', [Validators.minLength(2), Validators.maxLength(1024)]));
  }

  getGroupTypes() {
    const param = new PageParam();
    param.pageNum = 1;
    param.pageSize = 1000;

    this._api.getGroupTypeList(param).subscribe((resp) => {
      if (resp.code == Consts.RESP_OK && resp.data) {
        this.groupTypes = resp.data;
      }
    });
  }

  onGroupTypeChange(id: number) {
    const param = new GroupQueryParam();
    param.groupTypeId = id;
    param.pageNum = 1;
    param.pageSize = 1000;

    this._api.getGroupList(param).subscribe((resp) => {
      if (resp.code == Consts.RESP_OK && resp.data) {
        this.groups = resp.data;
      }
    });
  }

  initParam(role: RoleDto) {
    this.addForm.patchValue({ roleName: role.roleName });
    this.addForm.patchValue({ roleKey: role.roleKey });
    console.log(`patch enabled to ${role.enabled}`);
    this.addForm.patchValue({ enabled: role.enabled });
    this.addForm.patchValue({ remark: role.remark });

    const selectedKeys = role.menus.map(x => x.menuId.toString());
    const preSelectedKeys: Set<string> = new Set();
    for (const key of selectedKeys) {
      preSelectedKeys.add(key);
    }
    this.defaultCheckedKeys = Array.from(preSelectedKeys);
    console.log(`set pre checked key : ${this.defaultCheckedKeys.join(',')}`);

    // this.selectedGroupTypeId = role.groupTypeId ?? 0;

    // if (this.selectedGroupTypeId != null) {
    //   this.onGroupTypeChange(this.selectedGroupTypeId);
    // }
    this.selectedGroupIds = role.groups.map(x => x.groupId);
  }

  getMenus() {
    const param = new MenuQueryParam();
    param.withButton = true;
    param.pageNum = 1;
    param.pageSize = 10000;

    this._api.getMenuTreePage(param).subscribe((resp) => {
      if (resp.code == Consts.RESP_OK && resp.data) {
        const data = resp.data;
        this.convertToTreeNodes(data);

        // 需要在获得权限之后，再设置preSelectedKeys
        this.modeSubject.subscribe((value) => {
          this.editMode = value.mode;
    
          if (this.editMode == EditMode.ADD) {
            this.addForm.get(ROLE_NAME)?.addValidators([Validators.required]);
            this.addForm.get(ROLE_KEY)?.addValidators([Validators.required]);
            this.addForm.get(ORDER_NUM)?.addValidators([Validators.required]);
          } else {
            this._api.getRoleDetail(value.roleId!).subscribe((resp) => {
              if (resp.code == Consts.RESP_OK && resp.data) {
                this.role = resp.data;
                this.initParam(this.role!);
              }
            });
          }
        });
      }
    });
  }

  onSubmit(event: UIEvent) {
    event.preventDefault();

    if (this.editMode == this.modeEnum.ADD) {
      this.onCreate();
    } else {
      this.onUpdate();
    }
  }

  onCreate() {
    this.submitted = true;
    if (!this.addForm.valid) {
      console.log('addform not valid');
      return;
    }

    console.log('onAdd');
    const param = new AddRoleParam();

    param.roleName = this.addForm.get(ROLE_NAME)?.value;
    param.roleKey = this.addForm.get(ROLE_KEY)?.value;
    param.orderNum = this.addForm.get(ORDER_NUM)?.value;
    param.enabled = this.addForm.get(ENABLED)?.value;
    param.description = this.addForm.get(REMARK)?.value;
    // TODO check old and new menuIds
    param.menuIds = this.nzTreeComponent.getCheckedNodeList().map(x => Number(x.key));
    param.groupIds = this.selectedGroupIds;
    console.log(`Create with groupIds ${param.groupIds.join(',')}`);

    this.doAddRole(param);
  }

  doAddRole(param: AddRoleParam) {
    this._api.addRole(param).subscribe((resp) => {
      if (resp.code == Consts.RESP_OK) {
        this._message.info('Add ok');
        this.resetModal();
        this.addRoleEvent.emit(true);
      } else {
        this._message.warning('add error');
      }
    });
  }

  onUpdate() {
    this.submitted = true;
    if (!this.addForm.valid) {
      console.log('form error');
      return;
    }

    const param = new UpdateRoleParam();
    param.roleId = this.role!.roleId;
    param.roleName = this.addForm.get(ROLE_NAME)?.dirty ? this.addForm.get(ROLE_NAME)?.value : undefined;
    param.roleKey = this.addForm.get(ROLE_KEY)?.dirty ? this.addForm.get(ROLE_KEY)?.value : undefined;
    param.enabled = this.addForm.get(ENABLED)?.dirty ? this.addForm.get(ENABLED)?.value : undefined;
    param.remark = this.addForm.get(REMARK)?.dirty ? this.addForm.get(REMARK)?.value : undefined;

    const checkedNodes = this.nzTreeComponent.getCheckedNodeList();
    for (const checkedNode of checkedNodes) {
      console.log(`Update role checked ${checkedNode.key}`);
    }
    param.menuIds = checkedNodes.map(x => Number(x.key));

    param.groupIds = this.selectedGroupIds;
    console.log(`Update with groupIds ${param.groupIds.join(',')}`);

    this.doUpdate(param);
  }

  doUpdate(param: UpdateRoleParam) {
    this._api.updateRole(param).subscribe((resp) => {
      if (resp.code == Consts.RESP_OK) {
        this._message.info('Update Role OK');
        this.resetModal();
        this.addRoleEvent.emit(true);
      } else {
        this._message.warning('Update role error ' + resp.message);
      }
    });
  }

  onCancel(e: MouseEvent) {
    console.log('onCancel');
    e.preventDefault();

    this.addRoleEvent.emit(false);
  }

  get fm() {
    return this.addForm.controls;
  }

  convertToTreeNodes(menus: MenuDto[]) {
    this.selectedKeys = [];
    this.nodes = [];

    const parents = menus;
    for (const parent of parents) {
      const parentNode = this.convertParentNode(parent);
      this.nodes.push(parentNode);
    }
  }

  convertParentNode(menu: MenuDto): NzTreeNodeOptions {
    const result = this.convertToTreeNode(menu);

    if (menu.children != null) {
      for (const child of menu.children) {
        const childNode = this.convertParentNode(child);
        result.children?.push(childNode);
      }
    } else {
      result.isLeaf = true;
    }

    return result;
  }

  convertToTreeNode(menu: MenuDto): NzTreeNodeOptions {
    const result = {
      title: menu.menuName,
      key: menu.menuId.toString(),
      children: []
    };

    return result;
  }

  // Test tree node click
  nzClick(event: NzFormatEmitEvent): void {
    console.log(event);
  }

  nzCheck(event: NzFormatEmitEvent): void {
    console.log(event);
  }

  resetModal() {
    this.role = undefined;
    this.editMode = EditMode.ADD;
    this.submitted = false;
    this.expandedKeys = [];
    this.defaultCheckedKeys = [];
    this.selectedKeys = [];
  }
}
